﻿using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using IKEYCOMLib;
using System.Globalization;

namespace Panchina.Security.IKey1000
{
    public class IKeyManager
    {
        private IKEYCOMLib.CoiKey keyObj = null;//new IKEYCOMLib.CoiKey();
        private IKEYCLIENTLib.iKeyAuth authObj = null;
        
        private bool _opened = false;
        public bool Opened
        {
            get { return this._opened; }
            set { this._opened = value; }
        }

        public event IKEYCLIENTLib._IiKeyAuthEvents_InsertEventHandler OnInsert;
        public event IKEYCLIENTLib._IiKeyAuthEvents_RemoveEventHandler OnRemove;

        public IKeyManager()
        {
            Type t = Type.GetTypeFromCLSID(new Guid("47B3B650-CAE5-11D3-8D09-00A0C99FF62A"));

            keyObj = (IKEYCOMLib.CoiKey)Activator.CreateInstance(t);

            t = Type.GetTypeFromCLSID(new Guid("2669C745-AF54-4B50-B97C-7683123FEBA2"));

            authObj = (IKEYCLIENTLib.iKeyAuth)Activator.CreateInstance(t);

            ////keyObj = new IKEYCOMLib.CoiKey();

            ////authObj = new IKEYCLIENTLib.iKeyAuth();

            authObj.Insert += new IKEYCLIENTLib._IiKeyAuthEvents_InsertEventHandler(authObj_Insert);
            authObj.Remove += new IKEYCLIENTLib._IiKeyAuthEvents_RemoveEventHandler(authObj_Remove);
        }

        void authObj_Remove()
        {
            if (OnRemove != null)
            {
                OnRemove();
            }
        }

        void authObj_Insert()
        {
            //System.Windows.Forms.MessageBox.Show("insert from ikey");
            if (OnInsert != null)
            {
                OnInsert();
            }
        }

        public bool OpenDevice()
        {
            if ((this.Opened))
            {
                return true;
            }

            try
            {
                this.keyObj.CreateContext(0, IKeyapi.IKEY_API_VERSION);
                byte b = (byte)Microsoft.VisualBasic.Constants.vbEmpty;
                this.keyObj.OpenDevice(IKeyapi.IKEY_OPEN_FIRST, ref  b);
                this.Opened = true;
                return true;
            }
            catch (Exception ex)
            {
                //MsgBox(KeyExceptionStatus(ex.Message).Message)
                this.Opened = false;
                return false;
            }
        }


        public bool OpenNextDevice()
        {
            if ((this.Opened))
            {
                CloseDevice();
            }

            try
            {
                this.keyObj.CreateContext(0, IKeyapi.IKEY_API_VERSION);
                byte b = (byte)Microsoft.VisualBasic.Constants.vbEmpty;
                this.keyObj.OpenDevice(IKeyapi.IKEY_OPEN_NEXT, ref b);
                this.Opened = true;
                return true;
            }
            catch (Exception ex)
            {
                //MsgBox(KeyExceptionStatus(ex.Message).Message)
                this.Opened = false;
                return false;
            }
        }


        public void CloseDevice()
        {
            this.keyObj.CloseDevice();
            this.keyObj.DeleteContext();
            this.Opened = false;
        }


        public string GetFriendlyName()
        {
            if ((this.Opened == false))
            {
                this.OpenDevice();
            }

            string friendlyName = "";

            byte[] prop = new byte[32];

            try
            {

                byte b = (byte)Microsoft.VisualBasic.Constants.vbEmpty;
                this.keyObj.GetProperty(IKeyapi.IKEY_PROP_FRIENDLY_NAME, ref b, out  prop[0], 32);
                friendlyName = IKeyapi.ByteArrayToStr(prop);
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
            }

            return friendlyName;

        }


        public void SetFriendlyName(string name)
        {
            //byte[] prop = new byte[32];

            //IKeyapi.StringToByteArray(ref prop, name, name.Length);
           // IKeyapi.StrToByteArray(ref prop, name, name.Length);

            byte[] prop = IKeyapi.StrToByteArray(name);

            byte b = (byte)Microsoft.VisualBasic.Constants.vbEmpty;
            this.keyObj.SetProperty(IKeyapi.IKEY_PROP_FRIENDLY_NAME, ref b, ref prop[0], prop.Length);
        }

        public string GetSN()
        {
            string sn = "";
            byte[] prop = new byte[9];

            byte b = (byte)Microsoft.VisualBasic.Constants.vbEmpty;
            this.keyObj.GetProperty(IKeyapi.IKEY_PROP_SERNUM, ref b, out prop[0], 8);
            IKeyapi.HexToString(prop, ref sn, 8);

            return sn;
        }


        public bool CreateDir(int dirId, string dirName)
        {
            if ((this.Opened == false))
            {
                this.OpenDevice();
            }

            try
            {
                byte[] name = new byte[dirName.Length];

                IKeyapi.StringToByteArray(ref name, dirName, Strings.Len(dirName));

                byte[] guids = Guid.NewGuid().ToByteArray();

                IKeyapi.dirInfo.lId = dirId;
                IKeyapi.dirInfo.lFlags = 0;
                IKeyapi.dirInfo.lMaxEntries = 8;
                IKeyapi.dirInfo.lMaxSize = 256;


                this.keyObj.CreateDir(0, ref name[0], ref  guids[0], ref IKeyapi.dirInfo);

                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool DeleteDir(string dirName)
        {

            try
            {
                byte[] name = new byte[dirName.Length];

                IKeyapi.StringToByteArray(ref name, dirName, Strings.Len(dirName));


                int i = Convert.ToInt32(Microsoft.VisualBasic.Constants.vbEmpty);
                this.keyObj.DeleteDir(IKeyapi.IKEY_DIR_BY_NAME, i, ref name[0]);

                this.keyObj.Cleanup(0);

                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }

        }


        public bool ChangeDir(int dirId, string dirName)
        {

            try
            {
                byte[] name = new byte[dirName.Length];

                IKeyapi.StringToByteArray(ref name, dirName, Strings.Len(dirName));

                this.keyObj.ChangeDir(IKeyapi.IKEY_DIR_BY_NAME, dirId, ref name[0]);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }

        }

        public bool ChangeRootDir()
        {
            try
            {
                byte[] name = new byte[32];

                this.keyObj.ChangeDir(IKeyapi.IKEY_DIR_BY_ID, 0, ref name[0]);

                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool CreateFile(string dirName, int fileId, int fileSize, byte fileType, IKeyapi.AccessType access)
        {
            try
            {
                byte[] name = new byte[dirName.Length];

                IKeyapi.StringToByteArray(ref name, dirName, Strings.Len(dirName));

                int i = Convert.ToInt32(Microsoft.VisualBasic.Constants.vbEmpty);
                this.keyObj.ChangeDir(IKeyapi.IKEY_DIR_BY_NAME, i, ref name[0]);

                IKeyapi.fileInfo.lId = fileId;
                IKeyapi.fileInfo.lFlags = 0;
                IKeyapi.fileInfo.lFileSize = fileSize;
                IKeyapi.fileInfo.chFileType = fileType;
                IKeyapi.fileInfo.chReadAccess = access.Read;
                IKeyapi.fileInfo.chWriteAccess = access.Write;
                IKeyapi.fileInfo.chCryptAccess = access.Crypt;

                this.keyObj.CreateFile(0, ref IKeyapi.fileInfo);

                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool CreateFile(int dirId, int fileId, int fileSize, byte fileType, IKeyapi.AccessType access)
        {
            try
            {
                byte[] name = new byte[32];

                this.keyObj.ChangeDir(IKeyapi.IKEY_DIR_BY_ID, dirId, ref name[0]);

                IKeyapi.fileInfo.lId = fileId;
                IKeyapi.fileInfo.lFlags = 0;
                IKeyapi.fileInfo.lFileSize = fileSize;
                IKeyapi.fileInfo.chFileType = fileType;
                IKeyapi.fileInfo.chReadAccess = access.Read;
                IKeyapi.fileInfo.chWriteAccess = access.Write;
                IKeyapi.fileInfo.chCryptAccess = access.Crypt;

                this.keyObj.CreateFile(0, ref IKeyapi.fileInfo);

                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool DeleteFile(int fileId)
        {
            try
            {
                this.keyObj.DeleteFile(0, fileId);
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        public bool OpenFile(int fileId, byte fileType, IKeyapi.AccessType access)
        {
            try
            {
                IKeyapi.fileInfo.lId = fileId;
                IKeyapi.fileInfo.lFlags = 0;
                IKeyapi.fileInfo.chFileType = fileType;
                IKeyapi.fileInfo.chReadAccess = access.Read;
                IKeyapi.fileInfo.chWriteAccess = access.Write;
                IKeyapi.fileInfo.chCryptAccess = access.Crypt;

                this.keyObj.OpenFile(0, fileId, out IKeyapi.fileInfo);
                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool CloseFile()
        {
            try
            {
                this.keyObj.CloseFile();
                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool WriteData(string val)
        {
            try
            {
                //byte[] content = new byte[val.Length];
                //int size = 0;

                //IKeyapi.StringToByteArray(ref content, val, Strings.Len(val));
                //this.keyObj.Write(0, 0, ref content[0], Strings.Len(val), out size);
                //return true;

                int size = 0;

                byte[] content = IKeyapi.StrToByteArray(val);

                this.keyObj.Write(0, 0, ref content[0], content.Length, out size);

                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public string ReadData(int len)
        {
            try
            {
                //string ret = "";
                //byte[] content = new byte[len];
                //int size = 0;
                //this.keyObj.Read(0, 0, out content[0], len, out size);
                //IKeyapi.ByteArrayToString(ref ret, content, len);
                //return ret;

                string ret = "";
                byte[] content = new byte[len];
                int size = 0;
                this.keyObj.Read(0, 0, out content[0], len, out size);
                ret = IKeyapi.ByteArrayToStr(content);
                return ret.Replace("\0", "");
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return "";
            }
        }

        public bool Verify(string password)
        {
            byte[] pin = new byte[8];

            IKeyapi.StringToByteArray(ref pin, password, Strings.Len(password));

            try
            {
                this.keyObj.Verify(IKeyapi.IKEY_VERIFY_USER_PIN, ref pin[0], Strings.Len(password));
                return true;
            }
            catch (Exception ex)
            {
                //MsgHelper.InfoMSG(KeyExceptionStatus(ex.Message).Message);
                return false;
            }
        }

        public bool VerifyRegistration()
        {
            if ((this.Opened == false))
            {
                this.OpenDevice();
            }

            bool ret = false;

            IKeyapi.AccessType at = new IKeyapi.AccessType();
            at.Read = IKeyapi.IKEY_ACCESS_ANYONE;
            at.Write = IKeyapi.IKEY_ACCESS_ANYONE;

            if ((this.ChangeDir(1, "RegistInfo")))
            {
                if ((this.OpenFile(1, IKeyapi.IKEY_FILETYPE_DATA, at)))
                {
                    try
                    {
                        DateTime d = default(DateTime);
                        ret = DateTime.TryParseExact(this.ReadData(8), "yyyyMMdd", new CultureInfo("en-US", false).DateTimeFormat, System.Globalization.DateTimeStyles.None, out d);
                    }
                    catch (Exception ex)
                    {
                        ret = false;
                    }
                    this.CloseFile();
                }
            }
            else
            {
                ret = false;
            }

            return ret;

        }

        public IKeyapi.ReturnStatus KeyExceptionStatus(string exception)
        {
            IKeyapi.ReturnStatus ret = new IKeyapi.ReturnStatus();

            if (exception.Contains("0x00"))
            {
                ret.Message = "命令调用成功";
                ret.Code = IKeyapi.RB_SUCCESS;
            }
            else if (exception.Contains("0x80100001"))
            {
                ret.Message = "打开驱动出现问题或驱动没有加载。驱动丢失或没有发现驱动，或者设备无法在USB 接口检测到。检查此操作系统是否配置为支持 USB 接口。请检查您的安装。";
                ret.Code = IKeyapi.RB_CANNOT_OPEN_DRIVER;
            }
            else if (exception.Contains("0x80100002"))
            {
                ret.Message = "不兼容的驱动版本。也许程序库和驱动版本不兼容。请检查您的安装。";
                ret.Code = IKeyapi.RB_INVALID_DRVR_VERSION;
            }
            else if (exception.Contains("0x80100003"))
            {
                ret.Message = "发送给设备的命令无效。设备不支持一个从程序库产生的命令。当程序库不支持此设备时有可能发生此情况。";
                ret.Code = IKeyapi.RB_INVALID_COMMAND;
            }
            else if (exception.Contains("0x80100004"))
            {
                ret.Message = "访问拒绝。请提供合适的存取控制设置或者使用 iKey 编辑器检查设备的存取控制设置。";
                ret.Code = IKeyapi.RB_ACCESS_DENIED;
            }
            else if (exception.Contains("0x80100005"))
            {
                ret.Message = "计数器的值已经为0无法递减。";
                ret.Code = IKeyapi.RB_ALREADY_ZERO;
            }
            else if (exception.Contains("0x80100006"))
            {
                ret.Message = "无法发现设备。请检查操作系统是否配置为支持 USB 接口。";
                ret.Code = IKeyapi.RB_UNIT_NOT_FOUND;
            }
            else if (exception.Contains("0x80100007"))
            {
                ret.Message = "设备没有连接。无法从 USB 接口检测到设备。";
                ret.Code = IKeyapi.RB_DEVICE_REMOVED;
            }
            else if (exception.Contains("0x80100008"))
            {
                ret.Message = "从设备收到无效的响应。本不应发生。请重试、重新加载驱动并重新启动计算机。";
                ret.Code = IKeyapi.RB_COMMUNICATIONS_ERROR;
            }
            else if (exception.Contains("0x80100009"))
            {
                ret.Message = "请求访问目录不存在。请检查目录 ID 参数。";
                ret.Code = IKeyapi.RB_DIR_NOT_FOUND;
            }
            else if (exception.Contains("0x8010000A"))
            {
                ret.Message = "请求访问文件不存在。请检查文件 ID 参数。";
                ret.Code = IKeyapi.RB_FILE_NOT_FOUND;
            }
            else if (exception.Contains("0x8010000B"))
            {
                ret.Message = "存储区的内容已损坏。本不应该发生；请重试、清除所有内容并重新安装设备。设备可能被病毒感染。";
                ret.Code = IKeyapi.RB_MEM_CORRUPT;
            }
            else if (exception.Contains("0x8010000C"))
            {
                ret.Message = "硬件内部错误。本不应该发生；请重试、清除设备内容并重新安装设备。设备也许被病毒感染。";
                ret.Code = IKeyapi.RB_INTERNAL_HW_ERROR;
            }
            else if (exception.Contains("0x8010000D"))
            {
                ret.Message = "没有足够的响应空间。从设备产生；本不应该发生。请重试、重新加载驱动并重启操作系统。";
                ret.Code = IKeyapi.RB_INVALID_RESP_SIZE;
            }
            else if (exception.Contains("0x8010000E"))
            {
                ret.Message = "PIN 计数器为0并且不允许更多的重试。";
                ret.Code = IKeyapi.RB_PIN_EXPIRED;
            }
            else if (exception.Contains("0x8010000F"))
            {
                ret.Message = "文件或目录已存在。";
                ret.Code = IKeyapi.RB_ALREADY_EXISTS;
            }
            else if (exception.Contains("0x80100010"))
            {
                ret.Message = "没有足够的空间。分配给目录的空间不足。请重新创建一个更大容量的目录。";
                ret.Code = IKeyapi.RB_NOT_ENOUGH_MEMORY;
            }
            else if (exception.Contains("0x80100011"))
            {
                ret.Message = "无效的参数。请检查参数。";
                ret.Code = IKeyapi.RB_INVALID_PARAMETER;
            }
            else if (exception.Contains("0x80100012"))
            {
                ret.Message = "对齐错误。设备内部数据应为双字节对齐。请调整参数的对齐方式。";
                ret.Code = IKeyapi.RB_ALIGNMENT_ERROR;
            }
            else if (exception.Contains("0x80100013"))
            {
                ret.Message = "输入数据过长。请检查输入参数长度。";
                ret.Code = IKeyapi.RB_INPUT_TOO_LONG;
            }
            else if (exception.Contains("0x80100014"))
            {
                ret.Message = "文件类型或者文件内容无效。请检查文件 ID 或者使用 iKey 编辑器检查此内容。";
                ret.Code = IKeyapi.RB_INVALID_FILE_SELECTED;
            }
            else if (exception.Contains("0x80100015"))
            {
                ret.Message = "设备已经被另一个应用程序打开。请校验上下文结构是否正确。请确保设备在重新打开之间已经被关闭。";
                ret.Code = IKeyapi.RB_DEVICE_IN_USE;
            }
            else if (exception.Contains("0x80100016"))
            {
                ret.Message = "API 版本和程序库不兼容。";
                ret.Code = IKeyapi.RB_INVALID_API_VERSION;
            }
            else if (exception.Contains("0x80100017"))
            {
                ret.Message = "操作超时。";
                ret.Code = IKeyapi.RB_TIME_OUT_ERROR;
            }
            else if (exception.Contains("0x80100018"))
            {
                ret.Message = "没有发现指定的项目。";
                ret.Code = IKeyapi.RB_ITEM_NOT_FOUND;
            }
            else if (exception.Contains("0x80100019"))
            {
                ret.Message = "操作完成之前退出。";
                ret.Code = IKeyapi.RB_COMMAND_ABORTED;
            }
            else if (exception.Contains("0x801000FF"))
            {
                ret.Message = "从设备返回的无效状态。本不应该发生；也许一个更新的设备和老的程序库不兼容。请检查您的安装并使用 iKey 编辑器检查设备内容。";
                ret.Code = IKeyapi.RB_INVALID_STATUS;
            }
            else if (exception.Contains("0x80104001"))
            {
                ret.Message = "无法在当前目录或者 PATH 环境变量列出的目录中找到 iKey 1000 C API 程序库。";
                ret.Code = IKeyapi.RB_LIBRARY_NOT_FOUND;
            }
            else if (exception.Contains("0x80104002"))
            {
                ret.Message = "iKey 1000 C API 程序库的版本比2.0旧。";
                ret.Code = IKeyapi.RB_LIBRARY_OBSOLETE;
            }
            else if (exception.Contains("0x80104003"))
            {
                ret.Message = "iKey 1000 C API 程序库不包括iKey 1000 ActiveX 控件需要的函数。";
                ret.Code = IKeyapi.RB_LIBRARY_MISMATCH;
            }


            return ret;

        }
    }
}